# -*- coding: utf-8 -*-
# @Time : 2022/3/23 17:35
# @FileName: YieldRateDialog.py
# @Mail: lizhigen1996@aliyun.com

__author__ = 'Zhigen.li'



from PyQt5.QtChart import QChart, QLineSeries, QValueAxis, QChartView, QDateTimeAxis
import datetime
import time
import sys
from PyQt5.QtCore import Qt, QRect, QDateTime, QDate, QPoint, QPointF, pyqtSignal, QEvent
from PyQt5.QtGui import QPainter, QCursor, QColor, QBrush, QMouseEvent, QIcon
from PyQt5.QtWidgets import QToolTip, QWidget, QApplication, QGridLayout, QGraphicsSimpleTextItem, \
                            QPushButton, QSpacerItem, QSizePolicy, QMenu, QAction
from res.resource_rc import *
from Config.Config import CatchExceptions

class MyChartView(QChartView):
    mouseMoving = pyqtSignal(QPointF)

    def __init__(self, chart, timeList, data):
        super(MyChartView, self).__init__(chart)
        self.timeList = timeList
        self.data = data
        self.m_coordItem = None
        self.mouseMoving.connect(self.onMouseMoving)

        self.serie_pointX = QLineSeries(self.chart())
        self.serie_pointY = QLineSeries(self.chart())
        self.serie_pointX.setName('PointX')
        self.serie_pointY.setName('PointY')
        self.serie_pointX.setVisible(False)
        self.serie_pointY.setVisible(False)
        self.chart().addSeries(self.serie_pointX)
        self.chart().addSeries(self.serie_pointY)

    def setAxis(self, axisX, axisY):
        self.axisX = axisX
        self.axisY = axisY
        self.chart().setAxisX(axisX, self.serie_pointX)
        self.chart().setAxisY(axisY, self.serie_pointX)
        self.chart().setAxisX(axisX, self.serie_pointY)
        self.chart().setAxisY(axisY, self.serie_pointY)

    @CatchExceptions
    def mouseMoveEvent(self, event: QMouseEvent):
        if not self.m_coordItem:
            self.m_coordItem = QGraphicsSimpleTextItem(self.chart())
            self.m_coordItem.setZValue(5)
            self.m_coordItem.show()

        self.m_coordItem.setVisible(False)
        curPos = event.pos()
        curVal = self.chart().mapToValue(curPos)
        timeArr = time.localtime(curVal.x() // 1000)
        timeStr = time.strftime("%Y/%m/%d", timeArr)

        # 时间并不是连续的，周末或节假日没有
        num = 15  # 最多15次
        idx = -1
        while num > 0:
            try:
                idx = self.timeList.index(timeStr)
                break
            except:
                t = datetime.datetime.strptime(timeStr, "%Y/%m/%d") - datetime.timedelta(days=1)
                timeStr = t.strftime("%Y/%m/%d")
            num -= 1

        if idx < 0:
            return super(MyChartView, self).mouseMoveEvent(event)

        text = '日期：{}\n'.format(self.timeList[idx])
        for d in self.data:
            s = '{}收益率：{}%\n'.format(d['name'], d['data'][idx][1])
            text += s
        text = text[:-1]

        self.m_coordItem.setText(text)
        self.m_coordItem.setPos(curPos.x(), curPos.y())

        self.m_coordItem.setVisible(True)
        self.mouseMoving.emit(curVal)

        # 隐藏部分图例
        for mark in self.chart().legend().markers():
            if 'Point' in mark.label().title():
                mark.setVisible(False)

        return super(MyChartView, self).mouseMoveEvent(event)

    @CatchExceptions
    def onMouseMoving(self, point: QPointF):
        self.serie_pointX.clear()
        self.serie_pointY.clear()

        self.serie_pointX.append(QPointF(self.axisX.min().toMSecsSinceEpoch(), point.y()))
        self.serie_pointX.append(QPointF(self.axisX.max().toMSecsSinceEpoch(), point.y()))
        self.serie_pointY.append(QPointF(point.x(), self.axisY.min()))
        self.serie_pointY.append(QPointF(point.x(), self.axisY.max()))
        self.serie_pointX.setVisible(True)
        self.serie_pointY.setVisible(True)

    def leaveEvent(self, a0: QEvent):
        self.serie_pointX.setVisible(False)
        self.serie_pointY.setVisible(False)
        self.m_coordItem.setVisible(False)


class YieldRateDialog(QWidget):
    curveCloseBtnClicked = pyqtSignal(bool)

    def __init__(self):
        super(YieldRateDialog, self).__init__()
        self.setMinimumHeight(280)
        self.gridLayout = QGridLayout(self)
        self.gridLayout.setObjectName("gridLayout")
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        # self.closeBtn = QPushButton(self)
        # self.closeBtn.setFlat(True)
        # self.closeBtn.setIcon(QIcon(':/Img/close.png'))
        # self.closeBtn.clicked.connect(self.curveCloseBtnClicked)
        # spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        # self.gridLayout.addItem(spacerItem, 0, 0, 1, 1)
        # self.gridLayout.addWidget(self.closeBtn, 0, 1, 1, 1)

        # 添加右击菜单
        self.setContextMenuPolicy(Qt.CustomContextMenu)  # 可弹出右键菜单
        self.popMenu = QMenu(self)
        self.closeAction = QAction()
        self.closeAction.setText('关闭此界面')
        self.popMenu.addAction(self.closeAction)
        self.closeAction.triggered.connect(self.curveCloseBtnClicked)
        # 右键点击事件
        self.customContextMenuRequested.connect(self.onShowMenu)

        self.timeList = []

    @CatchExceptions
    def showPlot(self, data, title):
        self.data = data
        for idx, d in enumerate(data):
            for sd in d['data']:
                timeArr = time.localtime(sd[0] // 1000)
                timeStr = time.strftime("%Y/%m/%d", timeArr)
                if idx == 0:
                    self.timeList.append(timeStr)
                t = datetime.datetime.strptime(timeStr, "%Y/%m/%d")
                sd[0] = t

        # 执行折线视图函数
        self.create_chart(data, title)

    @CatchExceptions
    def create_chart(self, data, title):
        self.setWindowTitle(title)
        # 创建折线视图窗口
        chart = QChart(title=title)
        chart.setContentsMargins(0, 0, 0, 0)
        # chart.setBackgroundVisible(visible=False)      # 背景色透明
        chart.setBackgroundBrush(QBrush(QColor("#FFFFFF")))     # 改变图背景色
        chart.setAnimationOptions(QChart.AllAnimations)

        #  图形项默认无法接收悬停事件，可以使用QGraphicsItem的setAcceptHoverEvents()函数使图形项可以接收悬停事件。
        chart.setAcceptHoverEvents(True)

        # 执行创建折线的函数
        axisX, axisY = self.create_series(data, chart)
        chartView = MyChartView(chart, self.timeList, self.data)
        chartView.setContentsMargins(0, 0, 0, 0)
        chartView.setAxis(axisX, axisY)
        # self.gridLayout.addWidget(chartView, 1, 0, 1, 2)
        # self.gridLayout.setRowStretch(0, 1)
        # self.gridLayout.setRowStretch(1, 15)
        self.gridLayout.addWidget(chartView, 0, 0, 1, 1)
        chartView.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
        chartView.raise_()

    @CatchExceptions
    def create_series(self, data, chart):
        fundRate = []
        for d in data:
            for dd in d['data']:
                fundRate.append(dd[1])
        # 坐标轴
        axisX = QDateTimeAxis()
        # if len(data[0]['data']) > 8:
        #     axisX.setTickCount(8)
        # else:
        #     axisX.setTickCount(len(data[0]['data']))

        axisX.setFormat('yyyy/MM/dd')
        axisX.setTitleText('日期')
        chart.addAxis(axisX, Qt.AlignBottom)
        axisY = QValueAxis()
        axisY.setLabelFormat('%.2f')
        axisY.setTitleText('收益率')
        axisY.setMin(min(fundRate))
        axisY.setMax(max(fundRate))
        chart.addAxis(axisY, Qt.AlignLeft)

        # 创建折线的函数
        for d in data:
            # 创建曲线
            series = QLineSeries(chart)
            # 设置折线名
            series.setName(d['name'])
            for dd in d['data']:
                qtData = QDateTime()
                qtData.setDate(QDate(dd[0].year, dd[0].month, dd[0].day))
                series.append(qtData.toMSecsSinceEpoch(), dd[1])

            if len(d['data']) < 40:
                series.setPointsVisible(True)  # 显示圆点
            # 鼠标悬停连接事件
            # series.hovered.connect(self.onSeriesHoverd)

            chart.addSeries(series)  # 添加折线到视图窗口
            # series.attachAxis(axisX)
            # series.attachAxis(axisY)
            chart.setAxisX(axisX, series)
            chart.setAxisY(axisY, series)

        return axisX, axisY

    @CatchExceptions
    def onSeriesHoverd(self, point, state):
            # 鼠标悬停事件(底部x,y)
            if state and not QToolTip.isVisible():
                try:
                    name = self.sender().name()
                except:
                    name = ""

                timeArr = time.localtime(point.x() // 1000)
                timeStr = time.strftime("%Y/%m/%d", timeArr)

                # 时间并不是连续的，周末或节假日没有
                num = 15  # 最多15次
                idx = -1
                while num > 0:
                    try:
                        idx = self.timeList.index(timeStr)
                        break
                    except:
                        t = datetime.datetime.strptime(timeStr, "%Y/%m/%d") - datetime.timedelta(days=1)
                        timeStr = t.strftime("%Y/%m/%d")
                    num -= 1

                if idx < 0:
                    return

                text = '日期：{}\n'.format(self.timeList[idx])
                for d in self.data:
                    s = '{}收益率：{}%\n'.format(d['name'], d['data'][idx][1])
                    text += s
                text = text[:-1]

                QToolTip.showText(QCursor.pos(), text, self, self.rect(), 50000)

    def closeEvent(self, a0):
        super(YieldRateDialog, self).closeEvent(a0)
        del self

    def onShowMenu(self, pos):
        self.popMenu.exec(QCursor.pos())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    # 初始化所有视图
    login = YieldRateDialog()
    data = [{'data': [[1649174400000.0, 0.0], [1649260800000.0, -0.75], [1649347200000.0, 0.0], [1649606400000.0, 1.6], [1649692800000.0, 1.06], [1649779200000.0, 1.29], [1649865600000.0, 1.27], [1649952000000.0, 1.33], [1650211200000.0, 1.71], [1650297600000.0, 2.84], [1650384000000.0, 4.52], [1650470400000.0, 5.55], [1650556800000.0, 5.68], [1650816000000.0, 3.73], [1650902400000.0, 2.75], [1650988800000.0, 3.31], [1651075200000.0, 3.92], [1651161600000.0, 4.38], [1651680000000.0, 3.81], [1651766400000.0, 3.88]], 'name': '华夏饲料豆粕期货ETF联'}, {'data': [[1649174400000.0, 0.0], [1649260800000.0, 0.03], [1649347200000.0, 0.11], [1649606400000.0, 0.73], [1649692800000.0, 1.14], [1649779200000.0, 1.66], [1649865600000.0, 1.91], [1649952000000.0, 2.2], [1650211200000.0, 2.81], [1650297600000.0, 2.66], [1650384000000.0, 1.67], [1650470400000.0, 2.48], [1650556800000.0, 2.83], [1650816000000.0, 1.87], [1650902400000.0, 0.83], [1650988800000.0, 1.0], [1651075200000.0, 0.91], [1651161600000.0, 2.03], [1651680000000.0, 1.69], [1651766400000.0, 1.55]], 'name': '同类平均'}, {'data': [[1649174400000.0, 0.0], [1649260800000.0, -1.28], [1649347200000.0, -0.78], [1649606400000.0, -3.84], [1649692800000.0, -1.97], [1649779200000.0, -2.91], [1649865600000.0, -1.7], [1649952000000.0, -1.76], [1650211200000.0, -2.29], [1650297600000.0, -3.02], [1650384000000.0, -4.53], [1650470400000.0, -6.29], [1650556800000.0, -5.88], [1650816000000.0, -10.53], [1650902400000.0, -11.25], [1650988800000.0, -8.64], [1651075200000.0, -8.04], [1651161600000.0, -5.81], [1651680000000.0, -5.95], [1651766400000.0, -8.33]], 'name': '沪深300'}]
    title = '华夏饲料豆粕期货ETF联接A近一个月累计收益率走势'
    login.showPlot(data, title)
    login.resize(880, 300)
    login.show()
    sys.exit(app.exec_())

